package main

import (
	"errors"
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/data/validation"
	"fyne.io/fyne/v2/dialog"
	"fyne.io/fyne/v2/widget"
	"log"
	"regexp"
	"sort"
	"strconv"
)

var bc *BtcContext

func NewBtcFrame(w fyne.Window) *fyne.Container {
	defer func() {
		if e := recover(); e != nil {
			log.Println(e)
		}
	}()
	top := NewTop(w)

	area := NewLogArea()

	export := NewExport(w)
	box := container.NewVBox(top, widget.NewSeparator(), area, widget.NewSeparator(), export)
	setting.Loan(bc)
	setting.LoanOut()
	return box
}

func NewExport(w fyne.Window) *container.Split {

	box := container.NewHBox()

	left(w, bc, box)

	max := 20

	grid := container.NewAdaptiveGrid(5)
	bc.Part = NewPair(max, grid)

	left := container.NewVScroll(container.NewVBox(box, grid))

	//right
	right := container.NewVBox()

	entry := widget.NewEntry()
	bc.OutExcel = entry

	button := widget.NewButton("输出excel目录", func() {
		dialog.NewFolderOpen(func(uri fyne.ListableURI, err error) {
			if uri != nil {
				bc.OutExcel.SetText(uri.Path())
			}

		}, w).Show()
	})

	entry2 := widget.NewEntry()
	bc.OutChart = entry2
	button2 := widget.NewButton("输出图表目录", func() {
		dialog.NewFolderOpen(func(uri fyne.ListableURI, err error) {
			if uri != nil {
				bc.OutChart.SetText(uri.Path())
			}
		}, w).Show()
	})

	upFilter := func(input []*RankPair) []*RankPair {
		var rp []*RankPair
		for _, v := range input {
			if v.Left >= 0 && v.Right > 0 {
				rp = append(rp, v)
			}
		}

		return rp
	}

	downFilter := func(input []*RankPair) []*RankPair {
		var rp []*RankPair
		for _, v := range input {
			if v.Left < 0 && v.Right < 0 {
				rp = append(rp, v)
			}
		}

		sort.Slice(rp, func(i, j int) bool {
			return rp[i].Index < rp[j].Index
		})

		for k, v := range rp {
			v.Index = k
		}

		return rp
	}

	outBtn0 := widget.NewButton("打开涨幅excel", func() {
		defer func() {
			if e := recover(); e != nil {
				err, re := e.(error)
				if re {
					bc.Log(err.Error())
				} else {
					bc.Log("打开失败")
				}
			}
		}()
		if bc.Max.Text == "" {
			dialog.NewInformation("tips", "请输入最大值", w).Show()
			return
		}

		OpenRateExcel(upFilter, "涨幅")
	})
	outBtn1 := widget.NewButton("打开赚钱系数excel", func() {
		defer func() {
			if e := recover(); e != nil {
				err, re := e.(error)
				if re {
					bc.Log(err.Error())
				} else {
					bc.Log("打开失败")
				}
			}
		}()
		if bc.Max.Text == "" {
			dialog.NewInformation("tips", "请输入最大值", w).Show()
			return
		}
		OpenLoseExcel("win", true, upFilter)
	})

	outBtn3 := widget.NewButton("打开砸盘系数excel", func() {
		defer func() {
			if e := recover(); e != nil {
				err, re := e.(error)
				if re {
					bc.Log(err.Error())
				} else {
					bc.Log("打开失败")
				}
			}
		}()
		if bc.Max.Text == "" {
			dialog.NewInformation("tips", "请输入最大值", w).Show()
			return
		}
		OpenLoseExcel("lose", true, upFilter)
	})

	outBtn6 := widget.NewButton("打开升钱excel", func() {
		defer func() {
			if e := recover(); e != nil {
				err, re := e.(error)
				if re {
					bc.Log(err.Error())
				} else {
					bc.Log("打开失败")
				}
			}
		}()
		if bc.Max.Text == "" {
			dialog.NewInformation("tips", "请输入最大值", w).Show()
			return
		}

		OpenLoseExcel("lose", true, downFilter)
	})

	outBtn5 := widget.NewButton("打开跌幅excel", func() {
		defer func() {
			if e := recover(); e != nil {
				err, re := e.(error)
				if re {
					bc.Log(err.Error())
				} else {
					bc.Log("打开失败")
				}
			}
		}()
		if bc.Max.Text == "" {
			dialog.NewInformation("tips", "请输入最大值", w).Show()
			return
		}

		OpenRateExcel(downFilter, "跌幅")
	})
	outBtn4 := widget.NewButton("打开亏钱excel", func() {
		defer func() {
			if e := recover(); e != nil {
				err, re := e.(error)
				if re {
					bc.Log(err.Error())
				} else {
					bc.Log("打开失败")
				}
			}
		}()
		if bc.Max.Text == "" {
			dialog.NewInformation("tips", "请输入最大值", w).Show()
			return
		}
		OpenLoseExcel("win", true, downFilter)
	})

	maxEntry := widget.NewEntry()
	maxEntry.SetText("10")
	maxForm := widget.NewFormItem("生成显示最大抓取数量", maxEntry)
	form := widget.NewForm(maxForm)

	bc.Max = maxEntry

	outBtn2 := widget.NewButton("打开图表", func() {
		defer func() {
			if e := recover(); e != nil {
				err, re := e.(error)
				if re {
					bc.Log(err.Error())
				} else {
					bc.Log("打开失败")
				}
			}
		}()
		if bc.Max.Text == "" {
			dialog.NewInformation("tips", "请输入最大值", w).Show()
			return
		}
		OpenChart(upFilter, downFilter)
	})

	btns0 := container.NewHBox(outBtn5, outBtn4, outBtn6)
	btns := container.NewHBox(outBtn0, outBtn1, outBtn3)

	right.Add(button)
	right.Add(entry)
	right.Add(btns)
	right.Add(btns0)
	right.Add(form)
	right.Add(widget.NewSeparator())
	right.Add(button2)
	right.Add(entry2)
	right.Add(outBtn2)

	split := container.NewHSplit(left, right)
	return split
}

func left(w fyne.Window, context *BtcContext, box *fyne.Container) {
	startbtn := widget.NewButton("加载", func() {
		dialog.NewConfirm("", "加载", func(b bool) {
			if b {
				setting.Loan(context)
				setting.LoanOut()
				bc.ApiKey.SetText(setting.loanApiKey())
			}
		}, w).Show()
	})

	stopbtn := widget.NewButton("保存", func() {
		dialog.NewConfirm("", "保存", func(b bool) {
			if b {
				setting.SavePair(context.Part)
				setting.SaveOutPut()
				setting.saveApiKey(bc.ApiKey.Text)
			}
		}, w).Show()
	})

	clearBtn := widget.NewButton("清空", func() {
		dialog.NewConfirm("", "清空", func(b bool) {
			if b {
				context.Clear()
			}
		}, w).Show()
	})

	box.Add(startbtn)
	box.Add(stopbtn)
	box.Add(clearBtn)
}

type PartLine struct {
	Name  string
	Left  *widget.Entry
	Right *widget.Entry
	Label *widget.Label
	Val   *widget.Label
	Index int
}

func (p *PartLine) Clear() {
	p.Left.SetText("")
	p.Right.SetText("")
}

func NewPartLine(name string, left *widget.Entry, right *widget.Entry, label *widget.Label, v2 *widget.Label) *PartLine {
	return &PartLine{Name: name, Left: left, Right: right, Label: label, Val: v2}
}

func (p *PartLine) Change(v string) {
	t := p.Left.Text + "%" + "-" + p.Right.Text + "%"
	p.Val.SetText(t)
}
func (p *PartLine) NewNumCheck(regexpstr, reason string) fyne.StringValidator {
	expression, err := regexp.Compile(regexpstr)
	if err != nil {
		fyne.LogError("Regexp did not compile", err)
		return nil
	}

	err = errors.New(reason)
	return func(text string) error {
		if text == "" {
			return nil
		}
		if expression != nil && !expression.MatchString(text) {
			return err
		}

		return nil // Nothing to validate with, same as having no validator.
	}
}
func (p *PartLine) LineValidat() fyne.StringValidator {

	return func(text string) error {
		if p.Left.Text != "" && p.Right.Text != "" {
			leftValue, e1 := strconv.Atoi(p.Left.Text)

			if e1 != nil {
				return errors.New("第" + strconv.Itoa(p.Index+1) + "行左侧 输入有误")
			}

			rightValue, e2 := strconv.Atoi(p.Right.Text)

			if e2 != nil {
				return errors.New("第" + strconv.Itoa(p.Index+1) + "行右侧 输入有误")
			}

			if leftValue < 0 && rightValue < 0 {
				if leftValue < rightValue {
					return errors.New("第" + strconv.Itoa(p.Index+1) + "行左>右 输入有误")
				}
			} else {
				if leftValue > rightValue {
					return errors.New("第" + strconv.Itoa(p.Index+1) + "行左>右 输入有误")
				}
			}

		}
		return nil
	}
}

func NewPair(m int, grid *fyne.Container) map[int]*PartLine {
	cache := make(map[int]*PartLine)
	for i := 0; i < m; i++ {
		l1 := widget.NewLabel("涨幅区间 " + strconv.Itoa(i+1))
		e1 := widget.NewEntry()

		e2 := widget.NewEntry()
		v := widget.NewLabel("值:")
		v2 := widget.NewLabel("%-%")

		line := NewPartLine("entry_"+strconv.Itoa(i), e1, e2, l1, v2)
		line.Index = i

		e1.Validator = validation.NewAllStrings(line.NewNumCheck(`\d`, "非法数字"), line.LineValidat())
		e2.Validator = validation.NewAllStrings(line.NewNumCheck(`\d`, "非法数字"), line.LineValidat())

		e1.OnChanged = line.Change
		e2.OnChanged = line.Change
		grid.Add(l1)
		grid.Add(e1)
		grid.Add(e2)
		grid.Add(v)
		grid.Add(v2)
		cache[i] = line
	}

	return cache
}

func NewLogArea() *fyne.Container {
	txtArea := widget.NewMultiLineEntry()
	bc.L = txtArea
	button := widget.NewButton("清空", func() {
		txtArea.SetText("")
	})
	scroll := container.NewHScroll(txtArea)
	bc.LS = scroll

	return container.NewVBox(scroll, button)
}
